<?php
/**
 * Инстелирования модуля в системе
 * 
 * @author nrnwest@gmail.com
 *
 */
class Arm_Module_Install
{
    
    /**
     * Имя устанавливаемого модуля.
     * @var string
     */
    private $_name;
    
    /**
     * Директория для файлов модуля
     * @var $_pathDirInstall unknown_type
     */
    private $_pathDirInstall;
    
    /**
     * Arm_Module_Sql_Pdo_Mysql 
     * @var Arm_Module_Sql_Pdo_Mysql 
     */
    private $_sql;
    
    /**
     * Тип архивов модуля.
     * 
     * @var string
     */
    const TYPE_ARCHIV_MODULE = '.tgz';
    
    public function __construct ($name)
    {
        $this->_name = trim(strtolower($name));
        $this->_sql = Arm_Db::getSqlObject(
        'Arm_Module_Sql', Arm_Db::getAdapter());
        $this->_pathDirInstall = Arm_Core::getPathModule(
        $this->_name) . 'install/';
    }
    /**
     * Инстеляция модуля в системе.
     */
    public function install ()
    {
        /**
         * 1) Удаления всех таблиц модуля с базы
         * 2) Выполнения sql скрипта модуля
         * 
         * 3) Проверка если есть модуль в системной таблице модулей:
         * 3.1) Удаляем пункты меню пренадлежащие модулю.
         * 3.2) Удаляем меню пренадлижащие модулю
         * 4) Удаления модуля с системной таблици модулей
         * 
         * 5) Запись модуля в таблицу модулей системы
         * 6) Установка меню модулей
         * 7) Запуск модели install модуля если таковая существует, модель может выполнять любые дополнительные действия
         * которые нужны для модуля.
         */
        if($this->_name !== 'admin' and $this->_name !== 'user') {
            $this->delTables();
            $this->runSqlModule();
        }
        $this->delModuleSystemTables();
        $this->writeModuleSystemTable();
        $this->writeMenuModule();
        // запись меню управления модуля.
        
        // запись страниц модуля
        $page = new Arm_Page();
        $page->writePagesInstallModule($this->_name, 1);
        // запись cron команд если есть такие.
        $cron = new Arm_Cron();
        $cron->writeComandsModule(Arm_Module::getInstance()->getIdModule($this->_name));
        // Запустим модель которая должна быть запущена во время инстеляции
        // модуля.
        $this->runModelInstall();
    }
    
    
    
    /**
     * Запуск модели модуля {Module}_Model_Install если данная модель существует она должна наследовать Arm_Module_Model_Install
     * @throw Arm_Exception если не наследует модель базовый класс
     * @return Arm_Module_Model_Install
     */
    public function runModelInstall ()
    {
        $class = ucfirst($this->_name) . '_Install_Install';
        if (is_file(Arm_Core::getPathModule($this->_name) . 'install/Install.php') and class_exists($class, true)) {
            $model = new $class();
            if (! $model instanceof Arm_Module_Model_Install) {
                throw new Arm_Exception(Arm_Translate::_('Класс %s должен наследовать Arm_Module_Model_Install', $class));
            }
            $model->run();
            return $model;
        }
        return null;
    }
    /**
     * Удаляем все таблици модуля с системы.
     * @return void
     */
    public function delTables ()
    {
        $this->_sql->delTablesModule(
        $this->_name);
        return;
    }
    /**
     * Выполнения sql модуля, с директории модуль/install/mysq.sql
     * @return void
     */
    public function runSqlModule ()
    {
        $path = $this->_pathDirInstall . 'db/' . Arm_Db::getTypeServer() .
         '/' . $this->_name . '.sql';
        if (is_file($path) === false) {
            return;
        }
        $dump = new Arm_Db_Dump(
        Arm_Db::getAdapter());
        $dump->import($path);
        return;
    }
    /**
     * Удаления модуля с системных таблиц, и его данных с других 
     * таблиц где он упоминался.
     */
    public function delModuleSystemTables ()
    {
        $idModule = $this->_sql->delModule(
        $this->_name);
        if ($idModule === false) {
            return;
        }
        $navigation = new Arm_Navigation();
        $navigation->delMenuModule($idModule);
        $navigation->deleteModuleSystemMenu(
        $idModule);
        $cron = new Arm_Cron();
        $cron->deleteComands($idModule);
        return;
    }
    /**
     * Запись модуля в системную таблицу и его включение.
     */
    public function writeModuleSystemTable ()
    {
        $systemModule = Arm_Module::getInstance()->getSystemModule();
        $data = array();
        $data['name'] = $this->_name;
        $data['install'] = 1;
        $data['on'] = 1;
        $data['system'] = array_search(
        $this->_name, $systemModule) === false ? 0 : 1;
        $this->_sql->addModule($data);
        Arm_Module::resetInstance();
    }
    /**
     * Запись меню модуля
     */
    public function writeMenuModule ()
    {
        $navigation = new Arm_Navigation();
        $navigation->setMenuModule($this->_name);
        return;
    }
    /**
     * Деиснтеляциия модуля
     * @param int $mode если 0 только деинстелируем, 1 тоже что и 0 но плюс удаляем
     * файлы модуля с системы.
     */
    public function unInstall ($mode = 0)
    {
        // Arm_Log::system('Модуль ' . $this->_name . ' мод ' .$mode);
        // проверим что это не системный модуль
        if (Arm_Module::getInstance()->isModuleSystem(
        $this->_name)) {
            throw new Arm_Exception(
            Arm_Translate::_(
            'Модуль %s являеться системным потому его деинстелировать не возможно', 
            $this->_name));
        }
        $mode = (int) $mode;
        $this->delTables();
        $this->delModuleSystemTables();
        if ($mode === 1) {
            // удаляем файлы модуля.
            $deleteDirs = array();
            $deleteDirs[] = Arm_Core::getPathModule(
            $this->_name);
            $deleteDirs[] = Arm_Core::getPathPublicHtml() .
             'modules/' . $this->_name;
            $deleteDirs[] = Arm_Core::getPathTests() .
             'application/modules/' .
             $this->_name;
            $dirs = new Arm_File_Dir();
            foreach ($deleteDirs as $d) {
                $dirs->delete(
                $d);
            }
        }
    }
    /**
     * Создания архива для инстталирования модуля.
     * Архивы создаются в application/modules/istall/install/modules
     * 
     * @return void
     */
    public function createArchivInstall ()
    {
        $path = Arm_Core::getPathModule('install') . 'install/modules/' . $this->_name . self::TYPE_ARCHIV_MODULE;
        if (is_file($path)) {
            unlink($path);
        }
        $arciv = new Arm_Archive($path, true);
        $addDir = array(
        'application/modules/' . $this->_name . '/', 
        'public/modules/' . $this->_name . '/', 
        'tests/application/modules/' . $this->_name .
         '/');
        $arciv->addFolders($addDir, 
        dirname(Arm_Core::getPathApplication()));
        return;
    }
    /**
     * Установка модуля с архива.
     * 
     * @return void
     */
    public function installModuleArchiv ()
    {
        $path = Arm_Core::getPathModule('install') . 'install/modules/' . $this->_name . self::TYPE_ARCHIV_MODULE;
        if (false === is_file($path)) {
            throw new Arm_Module_Exception(
            Arm_Translate::_(
            'Не существует архива инстеляции модуля "%s", в директории 
           application/modules/install/modules/'));
        }
        $arciv = new Arm_Archive($path);
        $arciv->extract(dirname(Arm_Core::getPathApplication()));
        $this->install();
    }
}